﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Text;

namespace PBGenerator
{
    public class GenerateFile
    {
        public static string get_uft8(string unicodeString)
        {
            UTF8Encoding utf8 = new UTF8Encoding();
            byte[] encodedBytes = utf8.GetBytes(unicodeString);
            return utf8.GetString(encodedBytes);
        }

        public static void generate(Dictionary<string, OpcodeInfo> communications, string java_package, string cs_name_space)
        {
            GenerateFile.generateJavaOpDefine(communications, java_package);
            GenerateFile.generateCSharpOpDefine(communications, cs_name_space);
            GenerateFile.generateJavaConvert(communications, java_package);
            GenerateFile.generateCSharpConvert(communications, cs_name_space);
        }

        public static void generateCSharpConvert(Dictionary<string, OpcodeInfo> communications, string cs_name_space)
        {
            StringBuilder sb = new StringBuilder();
            sb.AppendLine("using System;");
            sb.AppendLine("using System.Collections.Generic;");
            sb.AppendLine("using System.IO;");
            sb.AppendLine("using ProtoBuf;");
            sb.AppendLine("using Google.Protobuf;");
            sb.AppendLine("using " + cs_name_space + ";");
            sb.AppendLine("namespace " + cs_name_space + "{");
            sb.AppendLine("   public class PBConvert{");
            sb.AppendLine("       public static Object toObject(Int32 opCode, byte[] objectBytes) {");
            sb.AppendLine("              return toObject(opCode, objectBytes, 0, objectBytes.Length);");
            sb.AppendLine("       }");
            sb.AppendLine("       public static Object toObject(Int32 opCode, byte[] objectBytes,int start,int count) {");
            sb.AppendLine("            Object result = null;");
            sb.AppendLine("            using (MemoryStream m = new MemoryStream(objectBytes,start,count)){");
            sb.AppendLine("                switch (opCode) { ");
            foreach (KeyValuePair<string, OpcodeInfo> communication in communications)
            {
                if (communication.Value.messages.Count > 0)
                {
                    sb.AppendLine("#region " + GenerateFile.get_uft8(communication.Key));
                    foreach (string opcode in communication.Value.messages)
                    {
                        sb.AppendLine("                    case OpDefine." + opcode + ":");
                        sb.AppendLine("                        result =ProtoBuf.Message."+ opcode+ ".Parser.ParseFrom(m);");
                        sb.AppendLine("                        break;");
                    }
                    sb.AppendLine("#endregion");
                }
            }
            sb.AppendLine("                    default:");
            sb.AppendLine("                        break;");
            sb.AppendLine("                }");
            sb.AppendLine("            }");
            sb.AppendLine("            return result;");
            sb.AppendLine("        }");
            sb.AppendLine("        public static byte[] toBytes(Int32 opCode,Object obj){");
            sb.AppendLine("            byte[] result = null;");
            sb.AppendLine("            using (MemoryStream m = new MemoryStream()){");
            sb.AppendLine("                IMessage msgObj = obj as IMessage;");
            sb.AppendLine("                msgObj.WriteTo(m);");
            sb.AppendLine("                m.Position = 0;");
            sb.AppendLine("                int length = (int)m.Length;");
            sb.AppendLine("                result = new byte[length];");
            sb.AppendLine("                m.Read(result, 0, length);");
            sb.AppendLine("            }");
            sb.AppendLine("            return result;");
            sb.AppendLine("        }");
            sb.AppendLine("   }");
            sb.AppendLine("}");
            FileInfo fileInfo = new FileInfo(Program.getAppPath() + "//generate//PBConvert.cs");
            //FileInfo fileInfo = new FileInfo("D://SVNUnity//communication//trunk//ProtoBuf//generate//PBConvert.cs");
            if (fileInfo.Exists)
            {
                fileInfo.Delete();
            }
            File.WriteAllText(fileInfo.FullName, sb.ToString(), new UTF8Encoding());
            GenerateFile.writeInfo(fileInfo.FullName);
        }

        public static void generateJavaConvert(Dictionary<string, OpcodeInfo> communications, string java_package)
        {
            StringBuilder sb = new StringBuilder();
            sb.AppendLine("package " + java_package + ";");
            sb.AppendLine("import " + java_package + ".PBMessage.*;");
            sb.AppendLine("import " + java_package + ".PBMessage;");
            sb.AppendLine("import com.google.protobuf.InvalidProtocolBufferException;");
            sb.AppendLine("import com.hutong.framework.convert.IConvert;");
            sb.AppendLine("public class PBConvert implements IConvert {");
            sb.AppendLine("\tpublic Object toObject(int opcode, byte[] objectBytes) throws InvalidProtocolBufferException {");
            sb.AppendLine("\t\tObject result = null;");
            sb.AppendLine("\t\tswitch (opcode) {");
            foreach (KeyValuePair<string, OpcodeInfo> communication in communications)
            {
                if (communication.Value.messages.Count > 0)
                {
                    foreach (string opcode in communication.Value.messages)
                    {
                        sb.AppendLine("\t\t\tcase OpDefine." + opcode + ":");
                        sb.AppendLine("\t\t\t\tresult=PBMessage." + opcode + ".parseFrom(objectBytes);");
                        sb.AppendLine("\t\t\t\tbreak;");
                    }
                }
            }
            sb.AppendLine("\t\t\tdefault:");
            sb.AppendLine("\t\t\t\tresult = null;");
            sb.AppendLine("\t\t\t\tbreak;");
            sb.AppendLine("\t\t}");
            sb.AppendLine("\t\treturn result;");
            sb.AppendLine("\t}");
            sb.AppendLine("\tpublic byte[] toBytes(int opcode, Object object) {");
            sb.AppendLine("\t\tbyte[] objectBytes = null;");
            sb.AppendLine("\t\tswitch (opcode) {");
            foreach (KeyValuePair<string, OpcodeInfo> communication in communications)
            {
                if (communication.Value.messages.Count > 0)
                {
                    foreach (string opcode in communication.Value.messages)
                    {
                        sb.AppendLine("\t\t\tcase OpDefine." + opcode + ":");
                        sb.AppendLine("\t\t\t    objectBytes = ((" + opcode + ") object).toByteArray();");
                        sb.AppendLine("\t\t\t    break;");
                    }
                }
            }
            sb.AppendLine("         default:");
            sb.AppendLine("             objectBytes = null;");
            sb.AppendLine("             break;");
            sb.AppendLine("\t\t}");
            sb.AppendLine("\t\treturn objectBytes;");
            sb.AppendLine(" }");
            sb.AppendLine("}");
            FileInfo fileInfo = new FileInfo(Program.getAppPath() + "//generate//PBConvert.java");
            //FileInfo fileInfo = new FileInfo("D://SVNUnity//communication//trunk//ProtoBuf//generate//PBConvert.java");
            if (fileInfo.Exists)
            {
                fileInfo.Delete();
            }
            File.WriteAllText(fileInfo.FullName, sb.ToString(), new UTF8Encoding());
            GenerateFile.writeInfo(fileInfo.FullName);
        }

        public static void generateCSharpOpDefine(Dictionary<string, OpcodeInfo> communications, string cs_name_space)
        {
            StringBuilder sb = new StringBuilder();
            sb.AppendLine("using System;");
            sb.AppendLine("using System.Collections.Generic;");
            sb.AppendLine("namespace " + cs_name_space + "{");
            sb.AppendLine("\tpublic class OpDefine {");
            foreach (KeyValuePair<string, OpcodeInfo> communication in communications)
            {
                if (communication.Value.messages.Count > 0)
                {
                    sb.AppendLine("#region " + GenerateFile.get_uft8(communication.Key));
                    int startRegion = communication.Value.startOpcode;
                    int endRegion = communication.Value.endOpcode;
                    int index = 1;
                    //foreach (string opcode in communication.Value.messages)
                    //{
                    //    sb.AppendLine(string.Concat(new object[]
                    //    {
                    //        "\t\tpublic const int ",
                    //        opcode,
                    //        "=",
                    //        startRegion + index,
                    //        ";"
                    //    }));
                    //    index++;
                    //}
                    foreach (KeyValuePair<string, string> kv in communication.Value.dicMessages)
                    {
                        sb.AppendLine(string.Concat(new object[]
                        {
                            "\t\tpublic const int ",
                            kv.Value,
                            "=",
                            kv.Key,
                            ";"
                        }));
                    }
                    sb.AppendLine("#endregion");
                }
            }
            sb.AppendLine("\t}");
            sb.AppendLine("}");
            FileInfo fileInfo = new FileInfo(Program.getAppPath() + "//generate//OpDefine.cs");
            //FileInfo fileInfo = new FileInfo("generate//OpDefine.cs");
            if (fileInfo.Exists)
            {
                fileInfo.Delete();
            }
            File.WriteAllText(fileInfo.FullName, sb.ToString(), new UTF8Encoding());
            GenerateFile.writeInfo(fileInfo.FullName);
        }


        public static void generateJavaOpDefine(Dictionary<string, OpcodeInfo> communications, string java_package)
        {
            StringBuilder sb = new StringBuilder();
            sb.AppendLine("package " + java_package + ";");
            sb.AppendLine("public class OpDefine {");
            foreach (KeyValuePair<string, OpcodeInfo> communication in communications)
            {
                if (communication.Value.messages.Count > 0)
                {
                    int startRegion = communication.Value.startOpcode;
                    int endRegion = communication.Value.endOpcode;
                    int index = 1;
                    //foreach (string opcode in communication.Value.messages)
                    //{
                    //    sb.AppendLine(string.Concat(new object[]
                    //    {
                    //        "\tpublic static final int ",
                    //        opcode,
                    //        "=",
                    //        startRegion + index,
                    //        ";"
                    //    }));
                    //    index++;
                    //}
                    foreach (KeyValuePair<string, string> kv in communication.Value.dicMessages)
                    {
                        sb.AppendLine(string.Concat(new object[]
                        {
                            "\tpublic static final int ",
                            kv.Value,
                            "=",
                            kv.Key,
                            ";"
                        }));
                    }
                }
            }
            sb.AppendLine("}");
            FileInfo fileInfo = new FileInfo(Program.getAppPath() + "//generate//OpDefine.java");
            //FileInfo fileInfo = new FileInfo( "D://SVNUnity//communication//trunk//ProtoBuf//generate//OpDefine.java");

            if (fileInfo.Exists)
            {
                fileInfo.Delete();
            }
            File.WriteAllText(fileInfo.FullName, sb.ToString(), new UTF8Encoding());
            GenerateFile.writeInfo(fileInfo.FullName);
        }

        private static void writeInfo(string fileNmae)
        {
            Program.writeInfo(fileNmae + "生成完成!!!");
        }
    }
}
